
package com.hlkj.pay.app.merchant.ext.impl.hnapay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.date.DatePattern;
import cn.hutool.json.JSONObject;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.constant.HnapayConstant;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.dto.HnapayAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.dto.HnapayConfig;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.utils.HttpUtils;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.utils.RecepitUtil;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.order.RefundOrderDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.MerchantUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 新生支付 正扫 反扫 通用处理
 * 
 * @author HlpayTeam
 * @date 2024/10/11 16:22
 */
@Slf4j
@Repository
public class HnapaySceneCommonPayOrder {

    /**
     * 新生支付查询支付订单
     *
     * @param channelPayOrderQueryContext
     */
    public void commonQueryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderQueryContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        HnapayConfig payConfig = getPayConfig(channelConfig, channelPayOrderQueryContext.getMerchantAppChannelDO());
        PayOrderDO payOrderDO = channelPayOrderQueryContext.getPayOrderDO();
        try {
            Map<String, String> orderQueryReq = new LinkedHashMap<>();
            orderQueryReq.put("version", "2.0");
            orderQueryReq.put("tranCode", "EXP08");
            orderQueryReq.put("merId", payConfig.getMerId());
            orderQueryReq.put("merOrderId", payOrderDO.getPayOrderNo());
            orderQueryReq.put("submitTime", DateUtils.dateToString(payOrderDO.getCreateTime(), DatePattern.PURE_DATE_PATTERN));
            orderQueryReq.put("signValue", RecepitUtil.sign(payConfig.getMchM2PrivateKey(), orderQueryReq));
            orderQueryReq.put("signType", "3");
            orderQueryReq.put("merAttach", "");
            orderQueryReq.put("charset", "1");

            log.info("新生支付订单查询req参数:{}", JsonUtils.toJsonString(orderQueryReq));
            String url = domain(channelPayOrderQueryContext.isTest()) + HnapayConstant.TRADE_QUERY;
            String response = HttpUtils.postForm(url, orderQueryReq);
            log.info("新生支付订单查询返回参数:{}", response);

            JSONObject queryRsp = JsonUtils.parseObj(response);
            if ("0000".equals(queryRsp.getStr("resultCode"))) {
                PayOrderDO updartePayOrderDO = new PayOrderDO();
                switch (queryRsp.getStr("orderStatus")) {
                    case "1":
                        updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode());
                        updartePayOrderDO.setSuccessTime(DateUtils.shanghaiDate(queryRsp.getStr("tranFinishTime"), DatePattern.PURE_DATETIME_PATTERN));
                        break;
                    case "0":
                        updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.PAYING.getCode());
                        break;
                    default:
                        updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.FAIL.getCode());
                        updartePayOrderDO.setBankMsg(queryRsp.getStr("orderFailedMsg"));
                        channelPayOrderQueryContext.setRemark(queryRsp.getStr("orderFailedMsg"));
                }

                updartePayOrderDO.setInsOrderNo(queryRsp.getStr("hnapayOrderId"));

                if (StringUtils.hasText(queryRsp.getStr("userId"))) {
                    updartePayOrderDO.setUserId(queryRsp.getStr("userId"));
                }

                if (StringUtils.hasText(queryRsp.getStr("bankOrderId")))
                    updartePayOrderDO.setChannelOrderNo(queryRsp.getStr("bankOrderId"));
                channelPayOrderQueryContext.setUpdartePayOrderDO(updartePayOrderDO);
            }
            else {
                String respDesc = queryRsp.getStr("errorMsg");
                channelPayOrderQueryContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelPayOrderQueryContext.setRemark(respDesc);
                }
                else {
                    channelPayOrderQueryContext.setRemark("新生支付提交支付订单查询返回错误信息为空,错误码为:" + queryRsp.getStr("resultCode"));
                }
            }
        }
        catch (Exception e) {
            log.error("新生支付查询支付订单请求失败 message:{}", e.getMessage(), e);
            channelPayOrderQueryContext.setRemark("新生支付查询支付订单请求失败,失败信息" + e.getMessage());
            channelPayOrderQueryContext.setProcessStatus(Boolean.FALSE);
        }
    }

    /**
     * 新生支付订单退款
     *
     * @param channelRefundPayOrderContext
     */
    public void commonRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelRefundPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        HnapayConfig payConfig = getPayConfig(channelConfig, channelRefundPayOrderContext.getMerchantAppChannelDO());

        PayOrderDO payOrderDO = channelRefundPayOrderContext.getPayOrderDO();
        RefundOrderDO refundOrderDO = channelRefundPayOrderContext.getRefundOrderDO();
        try {
            Map<String, String> refundReq = new LinkedHashMap<>();
            refundReq.put("version", "2.0");
            refundReq.put("tranCode", "EXP09");
            refundReq.put("merId", payConfig.getMerId());
            refundReq.put("merOrderId", refundOrderDO.getRefundOrderNo());
            refundReq.put("submitTime", DateUtils.getDateString(DatePattern.PURE_DATETIME_PATTERN));

            Map<String, String> bodyReq = new LinkedHashMap<>();
            bodyReq.put("orgMerOrderId", payOrderDO.getPayOrderNo());
            bodyReq.put("orgSubmitTime", DateUtils.dateToString(payOrderDO.getCreateTime(), DatePattern.PURE_DATETIME_PATTERN));
            bodyReq.put("orderAmt", MerchantUtils.bigDecimalToString2(payOrderDO.getAmount()));
            bodyReq.put("refundOrderAmt", MerchantUtils.bigDecimalToString2(refundOrderDO.getRefundAmount()));
            bodyReq.put("notifyUrl", channelRefundPayOrderContext.getNotifyUrl());

            refundReq.put("msgCiphertext", RecepitUtil.encrpt(bodyReq, payConfig.getHnaM2PublicKey()));
            refundReq.put("signValue", RecepitUtil.sign(payConfig.getMchM2PrivateKey(), refundReq));
            refundReq.put("signType", "3");
            refundReq.put("merAttach", "");
            refundReq.put("charset", "1");

            log.info("新生支付订单退款req参数:{}", JsonUtils.toJsonString(bodyReq));
            String url = domain(channelRefundPayOrderContext.isTest()) + HnapayConstant.REFUND_ORDER;
            String response = HttpUtils.postForm(url, refundReq);
            log.info("新生支付订单退款返回参数:{}", response);

            JSONObject ordeRsp = JsonUtils.parseObj(response);
            if ("0000".equals(ordeRsp.getStr("resultCode"))) {
                RefundOrderDO updateRefundOrderDO = new RefundOrderDO();
                updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUNDING.getCode());
                updateRefundOrderDO.setSuccessTime(System.currentTimeMillis());
                channelRefundPayOrderContext.setUpdateRefundOrderDO(updateRefundOrderDO);
            }
            else {
                String respDesc = ordeRsp.getStr("errorMsg");
                channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelRefundPayOrderContext.setRemark(respDesc);
                }
                else {
                    channelRefundPayOrderContext.setRemark("新生支付提交退款订单返回错误信息为空,错误码为:" + ordeRsp.getStr("resultCode"));
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("新生支付提交退款订单请求失败 message:{}", e.getMessage(), e);
            channelRefundPayOrderContext.setRemark("新生支付提交退款订单请求失败,失败信息" + e.getMessage());
            channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    /**
     * 新生支付订单退款状态查询
     *
     * @param channelRefundPayOrderContext
     */
    public void commonQueryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelRefundPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        HnapayConfig payConfig = getPayConfig(channelConfig, channelRefundPayOrderContext.getMerchantAppChannelDO());

        RefundOrderDO refundOrderDO = channelRefundPayOrderContext.getRefundOrderDO();
        try {
            Map<String, String> orderQueryReq = new LinkedHashMap<>();
            orderQueryReq.put("version", "2.0");
            orderQueryReq.put("tranCode", "EXP08");
            orderQueryReq.put("merId", payConfig.getMerId());
            orderQueryReq.put("merOrderId", refundOrderDO.getRefundOrderNo());
            orderQueryReq.put("submitTime", DateUtils.dateToString(refundOrderDO.getCreateTime(), DatePattern.PURE_DATE_PATTERN));
            orderQueryReq.put("signValue", RecepitUtil.sign(payConfig.getMchM2PrivateKey(), orderQueryReq));
            orderQueryReq.put("signType", "3");
            orderQueryReq.put("merAttach", "");
            orderQueryReq.put("charset", "1");

            log.info("新生支付订单退款查询req参数:{}", JsonUtils.toJsonString(orderQueryReq));
            String url = domain(channelRefundPayOrderContext.isTest()) + HnapayConstant.TRADE_QUERY;
            String response = HttpUtils.postForm(url, orderQueryReq);
            log.info("新生支付订单退款查询返回参数:{}", response);

            JSONObject refundRsp = JsonUtils.parseObj(response);
            if ("0000".equals(refundRsp.getStr("resultCode"))) {
                RefundOrderDO updateRefundOrderDO = new RefundOrderDO();
                switch (refundRsp.getStr("orderStatus")) {
                    case "1":
                        updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUND.getCode());//
                        updateRefundOrderDO.setSuccessTime(DateUtils.shanghaiDate(refundRsp.getStr("tranFinishTime"), DatePattern.PURE_DATETIME_PATTERN));
                        break;
                    case "0":
                        updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUNDING.getCode());
                        break;
                    default:
                        updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.FAIL.getCode());
                        break;
                }
                channelRefundPayOrderContext.setUpdateRefundOrderDO(updateRefundOrderDO);
            }
            else {
                String respDesc = refundRsp.getStr("errorMsg");
                channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelRefundPayOrderContext.setRemark(respDesc);
                }
                else {
                    channelRefundPayOrderContext.setRemark("新生支付提交退款订单返回错误信息为空,错误码为:" + refundRsp.getStr("resultCode"));
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("新生支付退款订单查询请求失败 message:{}", e.getMessage(), e);
            channelRefundPayOrderContext.setRemark("新生支付退款订单查询请求失败,失败信息" + e.getMessage());
            channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    public HnapayAppChannelParams appChannelParams(MerchantAppChannelDO merchantAppChannelDO) {
        return JsonUtils.parseObject(merchantAppChannelDO.getAppConfigJson(), HnapayAppChannelParams.class);
    }

    public String domain(boolean test) {
        return HnapayConstant.DOMAIN_PROD;
    }

    public Integer expireMinute(Long time) {
        if (time == null) {
            return 30;
        }
        return (int) (time - System.currentTimeMillis()) / 1000 / 60;
    }

    //转换是如果商户有单独配置 取商户配置
    public HnapayConfig getPayConfig(String channelConfig, MerchantAppChannelDO merchantAppChannelDO) {
        // 配置转换
        HnapayConfig payConfig = JsonUtils.parseObject(channelConfig, HnapayConfig.class);

        HnapayAppChannelParams ChannelParams = appChannelParams(merchantAppChannelDO);

        if (StringUtils.hasText(ChannelParams.getMerId()))
            payConfig.setMerId(ChannelParams.getMerId());

        if (StringUtils.hasText(ChannelParams.getHnaM2PublicKey()))
            payConfig.setHnaM2PublicKey(ChannelParams.getHnaM2PublicKey());

        if (StringUtils.hasText(ChannelParams.getMchM2PrivateKey()))
            payConfig.setMchM2PrivateKey(ChannelParams.getMchM2PrivateKey());
        return payConfig;
    }

}
